package com.angcyo.selenium.auto.parse

import com.angcyo.library.ex.patternList
import com.angcyo.selenium.auto.BaseControl
import com.angcyo.selenium.auto.action.Action
import com.angcyo.selenium.isValid
import org.openqa.selenium.Rectangle

/**
 * 数值表达式解析
 * Email:angcyo@126.com
 * @author angcyo
 * @date 2021/01/12
 */
class ValueParse(val control: BaseControl? = null) {

    var minRatio = 0.0000001
    var maxRatio = 0.9999999

    /**约等于的范围*/
    var aboutRatio = 10f

    /**全部解析*/
    fun parseRectValue(rectStr: String, bounds: Rectangle): RectValue {
        val leftValue = parseExpression(rectStr, "l:|left:", bounds.width.toFloat())
        val rightValue = parseExpression(rectStr, "r:|right:", bounds.width.toFloat())
        val topValue = parseExpression(rectStr, "t:|top:", bounds.height.toFloat())
        val bottomValue = parseExpression(rectStr, "b:|bottom:", bounds.height.toFloat())

        val widthValue = parseExpression(rectStr, "w:|width:", bounds.width.toFloat())
        val heightValue = parseExpression(rectStr, "h:|height:", bounds.height.toFloat())

        val aboutValue = parseExpression(rectStr, "a:|about:", bounds.width.toFloat())
        return RectValue(leftValue, rightValue, topValue, bottomValue, widthValue, heightValue, aboutValue)
    }

    /**
     * [valueExpression] "l:0.1 t:100 w:-20.1width:>=99width:abc99 h:300"
     * [regexPrefix] 正则前缀 "l:|left:" "w:|width:"
     * [ref] 比例参考值
     * */
    fun parseExpression(valueExpression: String, regexPrefix: String, ref: Float = 1f): ValueExpression {
        val result = ValueExpression()

        //支持的操作符
        val op = Action.OP

        //获取到关键的表达式文本 xx:>=200 或者 xx:%5>=2
        val expTextPattern = "(?<=$regexPrefix)(\\S+)".toPattern()
        val list1 = valueExpression.patternList(expTextPattern)
        list1.firstOrNull()?.let { expText ->
            //获取关键的表达式 >=200 或者 %5和>=2
            val expPattern = "([$op]*[-]?[\\d.]*\\d+)".toPattern()
            val list2 = expText.patternList(expPattern)
            val expValueList = mutableListOf<ValueExpression>()
            list2.forEach {
                toValueExp(it, op, ref)?.let {
                    expValueList.add(it)
                }
            }

            if (expValueList.size >= 1) {
                result.value = expValueList[0].value
                result.expression = expValueList[0].expression
            }

            if (expValueList.size >= 2) {
                result.outcome = expValueList[1]
            }
        }

        return result
    }

    fun toValueExp(text: String, op: String = Action.OP, ref: Float = 1f): ValueExpression? {
        //获取表达式 >= 或者 %和>=
        val opPattern = "([$op]*)".toPattern()
        //获取值 200 或者 5和2
        val valuePattern = "([-]?[\\d.]*\\d+)".toPattern()
        val opList = text.patternList(opPattern)
        val valueList = text.patternList(valuePattern)

        val firstValue = valueList.firstOrNull()?.toFloatOrNull()
        if (firstValue != null) {
            return ValueExpression().apply {
                value = parseValue(firstValue, ref)
                expression = opList.firstOrNull()
            }
        }
        return null
    }

    /**
     * 从表达式 "l:0.1 t:100 w:-20.1width:>=99width:abc99 h:300" 获取一个矩形对象
     * 无效的值使用[Int.MIN_VALUE]
     * 如果值在 [minRatio]~[maxRatio] 之间, 则使用屏幕比例
     * */
    fun parseRect(valueExpression: String?, bounds: Rectangle): Rectangle? {
        if (valueExpression.isNullOrEmpty()) {
            return null
        } else {
            val rectValue = parseRectValue(valueExpression, bounds)

            if (!rectValue.isValid()) {
                return null
            }

            val l: Float = rectValue.leftValue.value ?: Float.MIN_VALUE
            val r: Float = rectValue.rightValue.value ?: Float.MIN_VALUE
            val t: Float = rectValue.topValue.value ?: Float.MIN_VALUE
            val b: Float = rectValue.bottomValue.value ?: Float.MIN_VALUE

            val w: Float =
                rectValue.widthValue.value ?: (if (r.isValid() && l.isValid()) r - l else Float.MIN_VALUE)
            val h: Float =
                rectValue.heightValue.value ?: (if (b.isValid() && t.isValid()) r - l else Float.MIN_VALUE)

            return Rectangle(
                parseValue(l, bounds.width.toFloat()).toInt(),
                parseValue(t, bounds.height.toFloat()).toInt(),
                parseValue(h, bounds.height.toFloat()).toInt(),
                parseValue(w, bounds.width.toFloat()).toInt()
            )
        }
    }

    /**
     * 解析数值
     * [ref] 比例引用参考值*/
    fun parseValue(value: Float, ref: Float): Float {
        return if (value in minRatio..maxRatio) {
            value * ref
        } else {
            value
        }
    }

    /**
     * 判断[target]是否满足[expression]表达式
     * [target] 需要判断的值
     * [expression] 表达式
     * [value] 需要比较的值
     * [compareValue] 取模需要比较的值
     * */
    fun matchValue(target: Float, valueExp: ValueExpression?, aboutRef: Float = aboutRatio): Boolean {
        if (valueExp == null) {
            return true
        }
        val value = valueExp.value ?: return true

        return when (valueExp.expression) {
            ">=" -> target >= value
            "<=" -> target <= value
            ">" -> target > value
            "<" -> target < value
            "=" -> target == value
            "≈" -> target in (value - aboutRef)..(value + aboutRef)
            "%" -> {
                val dValue = target.toLong() % value.toLong()
                if (valueExp.outcome == null) {
                    dValue == 0L
                } else {
                    matchValue(dValue.toFloat(), valueExp.outcome!!, aboutRef)
                }
            }
            else -> target == value
        }
    }

    /**匹配矩形, 是否符合指定条件
     * leftPattern = "(?<=l:|left:)([-]?[\\d.]*\\d+)"
     * rightPattern = "(?<=r:|right:)([-]?[\\d.]*\\d+)"
     * topPattern = "(?<=t:|top:)([-]?[\\d.]*\\d+)"
     * bottomPattern = "(?<=b:|bottom:)([-]?[\\d.]*\\d+)"
     * widthPattern = "(?<=w:|width:)([-]?[\\d.]*\\d+)"
     * heightPattern = "(?<=h:|height:)([-]?[\\d.]*\\d+)"
     * [targetRect] 需要匹配的矩形
     * [rectStr] 包含矩形匹配参数的字符串
     * [bounds] 比例参考的矩形*/
    fun matchRect(targetRect: Rectangle, rectStr: String, rectValue: RectValue): Boolean {
        if (rectStr.isEmpty()) {
            //如果为空字符, 那么只要矩形有大小即可
            return targetRect.width > 0 && targetRect.height > 0
        }

        var result = true

        fun checkValue(targetValue: ValueExpression, target: Float) {
            if (result) {
                //值判断
                if (targetValue.value != null) {
                    result = matchValue(target, targetValue, rectValue.aboutValue.value ?: aboutRatio)
                }
            }
        }

        //判断
        checkValue(rectValue.widthValue, targetRect.width.toFloat())
        checkValue(rectValue.heightValue, targetRect.height.toFloat())
        checkValue(rectValue.leftValue, targetRect.x.toFloat())
        checkValue(rectValue.topValue, targetRect.y.toFloat())
        checkValue(rectValue.rightValue, (targetRect.x + targetRect.width).toFloat())
        checkValue(rectValue.bottomValue, (targetRect.y + targetRect.height).toFloat())
        return result
    }
}

/**
 * 数值表达式
 * 168
 * <168.1
 * <=168.1
 * >168.168
 * >=168.0
 * =168.8
 * %3>=6
 * %3=2
 * */
data class ValueExpression(
    /**表达式中的数值*/
    var value: Float? = null,

    /**运算符
     * >= <= % */
    var expression: String? = null,

    /**%3=2 中的=2*/
    var outcome: ValueExpression? = null,
)

data class RectValue(
    val leftValue: ValueExpression,
    val rightValue: ValueExpression,
    val topValue: ValueExpression,
    val bottomValue: ValueExpression,

    val widthValue: ValueExpression,
    val heightValue: ValueExpression,

    val aboutValue: ValueExpression,
)

fun RectValue.isValid() =
    leftValue.value != null || rightValue.value != null || topValue.value != null || bottomValue.value != null